home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / max_rgb.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-03-26  |  13.8 KB  |  539 lines

  1. /* max_rgb.c -- This is a plug-in for the GIMP (1.0's API)
  2.  * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
  3.  * Time-stamp: <2000-02-08 16:26:24 yasuhiro>
  4.  * Version: 0.35
  5.  *
  6.  * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
  7.  *
  8.  * May 2000 - tim copperfield [timecop@japan.co.jp]
  9.  *
  10.  * Added a preview mode.  After adding preview mode realised just exactly
  11.  * how useless this plugin is :)
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26.  */
  27.  
  28. #include "config.h"
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. #include <gtk/gtk.h>
  35.  
  36. #include <libgimp/gimp.h>
  37. #include <libgimp/gimpui.h>
  38.  
  39. #include "libgimp/stdplugins-intl.h"
  40.  
  41.  
  42. /* Replace them with the right ones */
  43. #define    PLUG_IN_NAME         "plug_in_max_rgb"
  44. #define SHORT_NAME         "max_rgb"
  45. #define PROGRESS_UPDATE_NUM  100
  46. #define PREVIEW_SIZE         128 
  47.  
  48. static void    query    (void);
  49. static void    run    (gchar      *name,
  50.              gint        nparams,
  51.              GimpParam  *param,
  52.              gint       *nreturn_vals,
  53.              GimpParam **return_vals);
  54.  
  55. static void        fill_preview_with_thumb (GtkWidget    *preview_widget, 
  56.                         gint32        drawable_id);
  57. static GtkWidget  *preview_widget          (GimpDrawable *drawable);
  58.  
  59. static GimpPDBStatusType main_function     (GimpDrawable *drawable, 
  60.                         gboolean      preview_mode);
  61.  
  62. static gint       dialog         (GimpDrawable *drawable);
  63. static void        ok_callback    (GtkWidget    *widget,
  64.                    gpointer      data);
  65. static void        radio_callback (GtkWidget    *widget, 
  66.                    gpointer      data);
  67.  
  68.  
  69. GimpPlugInInfo PLUG_IN_INFO =
  70. {
  71.   NULL,  /* init_proc  */
  72.   NULL,  /* quit_proc  */
  73.   query, /* query_proc */
  74.   run,   /* run_proc   */
  75. };
  76.  
  77. enum
  78. {
  79.   MIN_CHANNELS = 0,
  80.   MAX_CHANNELS = 1
  81. };
  82.  
  83. typedef struct
  84. {
  85.   gint max_p;  /* gint, gdouble, and so on */
  86. } ValueType;
  87.  
  88. typedef struct 
  89. {
  90.   gint run;
  91. } Interface;
  92.  
  93. static ValueType pvals = 
  94. {
  95.   MAX_CHANNELS
  96. };
  97.  
  98. static Interface interface =
  99. {
  100.   FALSE
  101. };
  102.  
  103. static guchar *preview_bits;
  104. static GtkWidget *preview;
  105.  
  106. MAIN ()
  107.  
  108. static void
  109. query (void)
  110. {
  111.   static GimpParamDef args [] =
  112.   {
  113.     { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive"},
  114.     { GIMP_PDB_IMAGE,    "image",    "Input image (not used)"},
  115.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  116.     { GIMP_PDB_INT32,    "max_p",    "1 for maximizing, 0 for minimizing"}
  117.   };
  118.   static gint nargs = sizeof (args) / sizeof (args[0]);
  119.  
  120.   gimp_install_procedure (PLUG_IN_NAME,
  121.               "Return an image in which each pixel holds only "
  122.               "the channel that has the maximum value in three "
  123.               "(red, green, blue) channels, and other channels "
  124.               "are zero-cleared",
  125.               "the help is not yet written for this plug-in since none is needed.",
  126.               "Shuji Narazaki (narazaki@InetQ.or.jp)",
  127.               "Shuji Narazaki",
  128.               "May 2000",
  129.                           N_("<Image>/Filters/Colors/Max RGB..."),
  130.               "RGB*",
  131.               GIMP_PLUGIN,
  132.               nargs, 0,
  133.               args, NULL);
  134. }
  135.  
  136. static void
  137. run (gchar      *name,
  138.      gint        nparams,
  139.      GimpParam  *param,
  140.      gint       *nreturn_vals,
  141.      GimpParam **return_vals)
  142. {
  143.   GimpDrawable    *drawable;
  144.   static GimpParam    values[1];
  145.   GimpPDBStatusType    status = GIMP_PDB_EXECUTION_ERROR;
  146.   GimpRunModeType    run_mode;
  147.   
  148.   run_mode = param[0].data.d_int32;
  149.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  150.  
  151.   *nreturn_vals = 1;
  152.   *return_vals = values;
  153.   
  154.   values[0].type = GIMP_PDB_STATUS;
  155.   values[0].data.d_status = status;
  156.  
  157.   switch (run_mode)
  158.     {
  159.     case GIMP_RUN_INTERACTIVE:
  160.       INIT_I18N_UI();
  161.       gimp_get_data (PLUG_IN_NAME, &pvals);
  162.       /* Since a channel might be selected, we must check wheter RGB or not. */
  163.       if (!gimp_drawable_is_rgb (drawable->id))
  164.     {
  165.       g_message (_("Max RGB: Can only operate on RGB drawables."));
  166.       return;
  167.     }
  168.       if (! dialog (drawable))
  169.     return;
  170.       break;
  171.     case GIMP_RUN_NONINTERACTIVE:
  172.       INIT_I18N();
  173.       /* You must copy the values of parameters to pvals or dialog variables. */
  174.       pvals.max_p = param[3].data.d_int32;
  175.       break;
  176.     case GIMP_RUN_WITH_LAST_VALS:
  177.       INIT_I18N();
  178.       gimp_get_data (PLUG_IN_NAME, &pvals);
  179.       break;
  180.     }
  181.   
  182.   status = main_function (drawable, FALSE);
  183.  
  184.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  185.     gimp_displays_flush ();
  186.   if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
  187.     gimp_set_data (PLUG_IN_NAME, &pvals, sizeof (ValueType));
  188.     g_free(preview_bits);
  189.  
  190.   values[0].type = GIMP_PDB_STATUS;
  191.   values[0].data.d_status = status;
  192. }
  193.  
  194. static GimpPDBStatusType
  195. main_function (GimpDrawable *drawable, 
  196.            gboolean      preview_mode)
  197. {
  198.   GimpPixelRgn  src_rgn, dest_rgn;
  199.   guchar    *src, *dest, *save_dest, *src_data, *dest_data;
  200.   gpointer   pr = NULL;
  201.   gint       x, y, x1, x2, y1, y2;
  202.   gint       gap, total, processed = 0;
  203.   gint       init_value, flag;
  204.   gint       bpp = 3;
  205.  
  206.   init_value = (pvals.max_p > 0) ? 0 : 255;
  207.   flag = (0 < pvals.max_p) ? 1 : -1;
  208.  
  209.   if (preview_mode) 
  210.     {
  211.       x1 = y1 = 0;
  212.       x2 = GTK_PREVIEW (preview)->buffer_width;
  213.       y2 = GTK_PREVIEW (preview)->buffer_height;
  214.       gap = 0; /* no alpha on preview */
  215.       bpp = GTK_PREVIEW (preview)->bpp;
  216.     } 
  217.   else 
  218.     {
  219.       gap = (gimp_drawable_has_alpha (drawable->id)) ? 1 : 0;
  220.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  221.       gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  222.       gimp_pixel_rgn_init (&src_rgn, drawable,
  223.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  224.       gimp_pixel_rgn_init (&dest_rgn, drawable,
  225.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  226.       pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  227.       gimp_progress_init ( _("Max RGB: Scanning..."));
  228.     }
  229.   
  230.   total = (x2 - x1) * (y2 - y1);
  231.   if (total < 1)
  232.     return GIMP_PDB_EXECUTION_ERROR;
  233.  
  234.   if (preview_mode) 
  235.     { /* preview mode.  here we go again. see nova.c 
  236.      I just don't want to write a prev_pixel_rgn_process
  237.      and then find out someone else coded a much cooler
  238.      preview widget / functions for GIMP */
  239.       src_data = g_malloc (GTK_PREVIEW (preview)->rowstride * y2);
  240.       memcpy (src_data, preview_bits, GTK_PREVIEW (preview)->rowstride * y2);
  241.       dest_data = g_malloc (GTK_PREVIEW (preview)->rowstride * y2);
  242.       save_dest = dest_data;
  243.       
  244.       for (y = 0; y < y2; y++)
  245.     {
  246.       src  = src_data  + y * GTK_PREVIEW (preview)->rowstride;
  247.       dest = dest_data + y * GTK_PREVIEW (preview)->rowstride;
  248.       
  249.       for (x = 0; x < x2; x++)
  250.         {
  251.           gint   ch, max_ch = 0;
  252.           guchar max, tmp_value;
  253.           
  254.           max = init_value;
  255.           for (ch = 0; ch < 3; ch++)
  256.         if (flag * max <= flag * (tmp_value = (*src++)))
  257.           {
  258.             if (max == tmp_value)
  259.               {
  260.             max_ch += 1 << ch;
  261.               }
  262.             else
  263.               {
  264.             max_ch = 1 << ch; /* clear memories of old channels */
  265.             max = tmp_value;
  266.               }
  267.           }
  268.           
  269.           for ( ch = 0; ch < 3; ch++)
  270.         *dest++ = (guchar)(((max_ch & (1 << ch)) > 0) ? max : 0);
  271.           
  272.           if (gap) 
  273.         *dest++ = *src++;
  274.         }
  275.     }
  276.       
  277.       memcpy (GTK_PREVIEW (preview)->buffer, save_dest, GTK_PREVIEW (preview)->rowstride * y2);
  278.       gtk_widget_queue_draw (preview);
  279.     } 
  280.   else 
  281.     { /* normal mode */
  282.       for (; pr != NULL; pr = gimp_pixel_rgns_process (pr))
  283.     {
  284.       for (y = 0; y < src_rgn.h; y++)
  285.         {
  286.           src = src_rgn.data + y * src_rgn.rowstride;
  287.           dest = dest_rgn.data + y * dest_rgn.rowstride;
  288.           
  289.           for (x = 0; x < src_rgn.w; x++)
  290.         {
  291.           gint   ch, max_ch = 0;
  292.           guchar max, tmp_value;
  293.           
  294.           max = init_value;
  295.           for (ch = 0; ch < 3; ch++)
  296.             if (flag * max <= flag * (tmp_value = (*src++)))
  297.               {
  298.             if (max == tmp_value)
  299.               {
  300.                 max_ch += 1 << ch;
  301.               }
  302.             else
  303.               {
  304.                 max_ch = 1 << ch; /* clear memories of old channels */
  305.                 max = tmp_value;
  306.               }
  307.             
  308.               }
  309.           for ( ch = 0; ch < 3; ch++)
  310.             *dest++ = (guchar)(((max_ch & (1 << ch)) > 0) ? max : 0);
  311.           
  312.           if (gap) 
  313.             *dest++=*src++;
  314.           
  315.           if ((++processed % (total / PROGRESS_UPDATE_NUM + 1)) == 0)
  316.             gimp_progress_update ((gdouble) processed / (gdouble) total); 
  317.         }
  318.         }
  319.     }
  320.       gimp_progress_update (1.0);
  321.       gimp_drawable_flush (drawable);
  322.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  323.       gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  324.       gimp_drawable_detach (drawable);
  325.     }
  326.   
  327.   return GIMP_PDB_SUCCESS;
  328. }
  329.  
  330.  
  331. /* dialog stuff */
  332. static gint
  333. dialog (GimpDrawable *drawable)
  334. {
  335.   GtkWidget *dlg;
  336.   GtkWidget *main_vbox;
  337.   GtkWidget *abox;
  338.   GtkWidget *frame;
  339.   GtkWidget *max;
  340.   GtkWidget *min;
  341.  
  342.   gimp_ui_init ("max_rgb", TRUE);
  343.  
  344.   dlg = gimp_dialog_new (_("Max RGB"), "max_rgb",
  345.              gimp_standard_help_func, "filters/max_rgb.html",
  346.              GTK_WIN_POS_MOUSE,
  347.              FALSE, TRUE, FALSE,
  348.  
  349.              _("OK"), ok_callback,
  350.              NULL, NULL, NULL, TRUE, FALSE,
  351.              _("Cancel"), gtk_widget_destroy,
  352.              NULL, 1, NULL, FALSE, TRUE,
  353.  
  354.              NULL);
  355.  
  356.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  357.               GTK_SIGNAL_FUNC (gtk_main_quit),
  358.               NULL);
  359.  
  360.   main_vbox = gtk_vbox_new (FALSE, 2);
  361.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0);
  362.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  363.   gtk_widget_show (main_vbox);
  364.  
  365.   frame = gtk_frame_new (_("Preview"));
  366.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  367.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  368.   gtk_widget_show (frame);
  369.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  370.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  371.   gtk_container_add (GTK_CONTAINER (frame), abox);
  372.   gtk_widget_show (abox);
  373.   frame = gtk_frame_new (NULL);
  374.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  375.   gtk_container_add (GTK_CONTAINER (abox), frame);
  376.   gtk_widget_show (frame);
  377.   preview = preview_widget (drawable);
  378.   gtk_container_add (GTK_CONTAINER (frame), preview);
  379.   main_function (drawable, TRUE);
  380.   gtk_widget_show (preview);
  381.   
  382.   frame = gimp_radio_group_new2 (TRUE, _("Parameter Settings"),
  383.                  radio_callback,
  384.                  &pvals.max_p, GINT_TO_POINTER (pvals.max_p),
  385.  
  386.                  _("Hold the Maximal Channels"),
  387.                  GINT_TO_POINTER (MAX_CHANNELS), &max,
  388.                  _("Hold the Minimal Channels"),
  389.                  GINT_TO_POINTER (MIN_CHANNELS), &min,
  390.  
  391.                  NULL);
  392.   gtk_object_set_data (GTK_OBJECT (max), "drawable", drawable);
  393.   gtk_object_set_data (GTK_OBJECT (min), "drawable", drawable);
  394.  
  395.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  396.   gtk_container_add (GTK_CONTAINER (main_vbox), frame);
  397.   gtk_widget_show (frame);
  398.  
  399.   gtk_widget_show (dlg);
  400.  
  401.   gtk_main ();
  402.   gdk_flush ();
  403.  
  404.   return interface.run;
  405. }
  406.  
  407. static void
  408. radio_callback (GtkWidget *widget, 
  409.         gpointer  data)
  410. {
  411.   GimpDrawable *drawable;
  412.  
  413.   gimp_radio_button_update (widget, data);
  414.  
  415.   if (GTK_TOGGLE_BUTTON (widget)->active)
  416.     {
  417.       drawable = gtk_object_get_data (GTK_OBJECT (widget), "drawable");
  418.       main_function (drawable, TRUE);
  419.     }
  420. }
  421.  
  422. static void
  423. ok_callback (GtkWidget *widget,
  424.          gpointer   data)
  425. {
  426.   interface.run = TRUE;
  427.  
  428.   gtk_widget_destroy (GTK_WIDGET (data));
  429. }
  430.  
  431. static GtkWidget *
  432. preview_widget (GimpDrawable *drawable)
  433. {
  434.   gint       size;
  435.   GtkWidget *preview;
  436.  
  437.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  438.   fill_preview_with_thumb (preview, drawable->id);
  439.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  440.   preview_bits = g_malloc (size);
  441.   memcpy (preview_bits, GTK_PREVIEW (preview)->buffer, size);
  442.  
  443.   return preview;
  444. }
  445.  
  446. static void
  447. fill_preview_with_thumb (GtkWidget *widget, 
  448.              gint32     drawable_ID)
  449. {
  450.   guchar  *drawable_data;
  451.   gint     bpp;
  452.   gint     x,y;
  453.   gint     width  = PREVIEW_SIZE;
  454.   gint     height = PREVIEW_SIZE;
  455.   guchar  *src;
  456.   gdouble  r, g, b, a;
  457.   gdouble  c0, c1;
  458.   guchar  *p0, *p1;
  459.   guchar  *even, *odd;
  460.  
  461.   bpp = 0; /* Only returned */
  462.   
  463.   drawable_data = 
  464.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  465.  
  466.   if (width < 1 || height < 1)
  467.     return;
  468.  
  469.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  470.  
  471.   even = g_malloc (width * 3);
  472.   odd  = g_malloc (width * 3);
  473.   src = drawable_data;
  474.  
  475.   for (y = 0; y < height; y++)
  476.     {
  477.       p0 = even;
  478.       p1 = odd;
  479.       
  480.       for (x = 0; x < width; x++) 
  481.     {
  482.       if(bpp == 4)
  483.         {
  484.           r =  ((gdouble)src[x*4+0])/255.0;
  485.           g = ((gdouble)src[x*4+1])/255.0;
  486.           b = ((gdouble)src[x*4+2])/255.0;
  487.           a = ((gdouble)src[x*4+3])/255.0;
  488.         }
  489.       else if(bpp == 3)
  490.         {
  491.           r =  ((gdouble)src[x*3+0])/255.0;
  492.           g = ((gdouble)src[x*3+1])/255.0;
  493.           b = ((gdouble)src[x*3+2])/255.0;
  494.           a = 1.0;
  495.         }
  496.       else
  497.         {
  498.           r = ((gdouble)src[x*bpp+0])/255.0;
  499.           g = b = r;
  500.           if(bpp == 2)
  501.         a = ((gdouble)src[x*bpp+1])/255.0;
  502.           else
  503.         a = 1.0;
  504.         }
  505.       
  506.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  507.         {
  508.           c0 = GIMP_CHECK_LIGHT;
  509.           c1 = GIMP_CHECK_DARK;
  510.         } 
  511.       else 
  512.         {
  513.           c0 = GIMP_CHECK_DARK;
  514.           c1 = GIMP_CHECK_LIGHT;
  515.         }
  516.       
  517.     *p0++ = (c0 + (r - c0) * a) * 255.0;
  518.     *p0++ = (c0 + (g - c0) * a) * 255.0;
  519.     *p0++ = (c0 + (b - c0) * a) * 255.0;
  520.     
  521.     *p1++ = (c1 + (r - c1) * a) * 255.0;
  522.     *p1++ = (c1 + (g - c1) * a) * 255.0;
  523.     *p1++ = (c1 + (b - c1) * a) * 255.0;
  524.     
  525.       } /* for */
  526.       
  527.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  528.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  529.       else
  530.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  531.  
  532.       src += width * bpp;
  533.     }
  534.  
  535.   g_free (even);
  536.   g_free (odd);
  537.   g_free (drawable_data);
  538. }
  539.